home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / mail / YAM22src.lha / YAM_FI.c < prev    next >
C/C++ Source or Header  |  2000-11-03  |  34KB  |  838 lines

  1. /***************************************************************************
  2.  
  3.  YAM - Yet Another Mailer
  4.  Copyright (C) 2000  Marcel Beck <mbeck@yam.ch>
  5.  
  6.  This program is free software; you can redistribute it and/or modify
  7.  it under the terms of the GNU General Public License as published by
  8.  the Free Software Foundation; either version 2 of the License, or
  9.  (at your option) any later version.
  10.  
  11.  This program is distributed in the hope that it will be useful,
  12.  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  GNU General Public License for more details.
  15.  
  16.  You should have received a copy of the GNU General Public License
  17.  along with this program; if not, write to the Free Software
  18.  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  
  20.  YAM Official Support Site :  http://www.yam.ch
  21.  YAM OpenSource project    :  http://sourceforge.net/projects/yamos/
  22.  
  23. ***************************************************************************/
  24.  
  25. #include "YAM.h"
  26.                      
  27. /***************************************************************************
  28.  Module: Find
  29. ***************************************************************************/
  30.  
  31. /// Global variables
  32. int Mode2Group[12] = { 0,0,0,0,1,2,1,2,4,4,4,3 };
  33. ///
  34. /// FI_MakeSubstringPattern
  35. //  Creates pattern for substring search
  36. void FI_MakeSubstringPattern(char *pattern)
  37. {
  38.    char npattern[SIZE_PATTERN];
  39.    sprintf(npattern, "#?%s#?", pattern);
  40.    strcpy(pattern, npattern);
  41. }
  42. ///
  43. /// FI_MatchString
  44. //  Matches string against pattern
  45. BOOL FI_MatchString(struct Search *search, char *string)
  46. {
  47.    switch (search->Compare)
  48.    {
  49.       case 0: return (BOOL)(search->CaseSens ? MatchPattern(search->Pattern, string) : MatchPatternNoCase(search->Pattern, string));
  50.       case 1: return (BOOL)(search->CaseSens ? !MatchPattern(search->Pattern, string) : !MatchPatternNoCase(search->Pattern, string));
  51.       case 2: return (BOOL)(search->CaseSens ? strcmp(string, search->Match) < 0 : Stricmp(string, search->Match) < 0);
  52.       case 3: return (BOOL)(search->CaseSens ? strcmp(string, search->Match) > 0 : Stricmp(string, search->Match) > 0);
  53.    }
  54. }
  55. ///
  56. /// FI_MatchListPattern
  57. //  Matches string against a list of patterns
  58. BOOL FI_MatchListPattern(struct Search *search, char *string)
  59. {
  60.    int i;
  61.    for (i = 0; i < search->List.Used; i++)
  62.       if (search->CaseSens ? MatchPattern(search->List.Data[i], string)
  63.                            : MatchPatternNoCase(search->List.Data[i], string)) return TRUE;
  64.    return FALSE;
  65. }
  66. ///
  67. /// FI_MatchPerson
  68. //  Matches string against a person's name or address
  69. BOOL FI_MatchPerson(struct Search *search, struct Person *pe)
  70. {
  71.    if (search->Compare == 4) return FI_MatchListPattern(search, search->PersMode ? pe->RealName : pe->Address);
  72.                         else return FI_MatchString(search, search->PersMode ? pe->RealName : pe->Address);
  73. }
  74. ///
  75. /// FI_SearchPatternFast
  76. //  Searches string in standard header fields
  77. BOOL FI_SearchPatternFast(struct Search *search, struct Mail *mail)
  78. {
  79.    struct ExtendedMail *email;
  80.    int j;
  81.    BOOL found = FALSE;
  82.  
  83.    switch (search->Fast)
  84.    {
  85.       case FS_FROM: 
  86.          if (FI_MatchPerson(search, &mail->From)) found = TRUE;
  87.          break;
  88.       case FS_TO:
  89.          if (FI_MatchPerson(search, &mail->To)) found = TRUE;
  90.          if (mail->Flags & MFLAG_MULTIRCPT) if (email = MA_ExamineMail(mail->Folder, mail->MailFile, NULL, TRUE))
  91.          {
  92.             for (j = 0; j < email->NoSTo; j++) if (FI_MatchPerson(search, &email->STo[j])) found = TRUE;
  93.             MA_FreeEMailStruct(email);
  94.          }
  95.          break;
  96.       case FS_CC:
  97.          if (mail->Flags & MFLAG_MULTIRCPT) if (email = MA_ExamineMail(mail->Folder, mail->MailFile, NULL, TRUE))
  98.          {
  99.             for (j = 0; j < email->NoCC; j++)  if (FI_MatchPerson(search, &email->CC[j])) found = TRUE;
  100.             MA_FreeEMailStruct(email);
  101.          }
  102.          break;
  103.       case FS_REPLYTO:
  104.          if (FI_MatchPerson(search, &mail->ReplyTo)) found = TRUE;
  105.         break;
  106.       case FS_SUBJECT:
  107.          if ((search->Compare == 4) ? FI_MatchListPattern(search, mail->Subject) : FI_MatchString(search, mail->Subject)) found = TRUE;
  108.          break;
  109.       case FS_DATE:
  110.          {
  111.             struct DateStamp *pdat = (struct DateStamp *)search->Pattern;
  112.             int cmp = (pdat->ds_Minute) ? CompareDates(&(mail->Date), pdat) : pdat->ds_Days-mail->Date.ds_Days;
  113.             if ((search->Compare == 0 && cmp == 0) ||
  114.                 (search->Compare == 1 && cmp != 0) ||
  115.                 (search->Compare == 2 && cmp > 0) ||
  116.                 (search->Compare == 3 && cmp < 0)) found = TRUE;
  117.             break;
  118.          }
  119.       case FS_SIZE:
  120.          {
  121.             long cmp = search->Size - mail->Size;
  122.             if ((search->Compare == 0 && cmp == 0) ||
  123.                 (search->Compare == 1 && cmp != 0) ||
  124.                 (search->Compare == 2 && cmp > 0) ||
  125.                 (search->Compare == 3 && cmp < 0)) found = TRUE;
  126.             break;
  127.          }
  128.  
  129.    }
  130.    return found;
  131. }
  132. ///
  133. /// FI_SearchPatternInBody
  134. //  Searches string in message body
  135. BOOL FI_SearchPatternInBody(struct Search *search, struct Mail *mail)
  136. {
  137.    char *rptr, *ptr, *cmsg;
  138.    BOOL found = FALSE;
  139.  
  140.    RE_InitPrivateRC(mail, PM_TEXTS);
  141.    rptr = cmsg = RE_ReadInMessage(4, RIM_QUIET);
  142.    while (*rptr && !found && !G->FI->Abort)
  143.    {
  144.       DoMethod(G->App,MUIM_Application_InputBuffered);
  145.       for (ptr = rptr; *ptr && *ptr != '\n'; *ptr++); *ptr = 0;
  146.       if (FI_MatchString(search, rptr)) found = TRUE;
  147.       rptr = ++ptr;
  148.    }
  149.    free(cmsg);
  150.    RE_FreePrivateRC();
  151.    return found;
  152. }
  153. ///
  154. /// FI_SearchPatternInHeader
  155. //  Searches string in header field(s)
  156. BOOL FI_SearchPatternInHeader(struct Search *search, struct Mail *mail)
  157. {
  158.    char *rptr, *line, fullfile[SIZE_PATHFILE];
  159.    BOOL found = FALSE;
  160.    FILE *fh;
  161.    int i;
  162.  
  163.    if (StartUnpack(GetMailFile(NULL, mail->Folder, mail), fullfile, mail->Folder))
  164.    {
  165.       if (fh = fopen(fullfile, "r"))
  166.       {
  167.          MA_ReadHeader(fh);
  168.         for (i = 0; i < Header.Used && !found; i++)
  169.          {
  170.             DoMethod(G->App,MUIM_Application_InputBuffered);
  171.             rptr = line = Header.Data[i];
  172.             if (*search->Field)
  173.                if (Strnicmp(line, search->Field, strlen(search->Field))) continue;
  174.                else rptr = Trim(&line[strlen(search->Field)+1]);
  175.             if ((search->Compare == 4) ? FI_MatchListPattern(search, rptr) : FI_MatchString(search, rptr)) found = TRUE;
  176.          }
  177.          FreeData2D(&Header);
  178.          fclose(fh);
  179.       }
  180.       FinishUnpack(fullfile);
  181.    }
  182.    return found;
  183. }
  184. ///
  185. /// FI_IsFastSearch
  186. //  Checks if quick search is available for selected header field
  187. int FI_IsFastSearch(char *field)
  188. {
  189.    if (!stricmp(field, "from"))     return FS_FROM;
  190.    if (!stricmp(field, "to"))       return FS_TO;
  191.    if (!stricmp(field, "cc"))       return FS_CC;
  192.    if (!stricmp(field, "reply-to")) return FS_REPLYTO;
  193.    if (!stricmp(field, "subject"))  return FS_SUBJECT;
  194.    if (!stricmp(field, "date"))     return FS_DATE;
  195.    return FS_NONE;
  196. }
  197. ///
  198. /// FI_GenerateListPatterns
  199. //  Reads list of patterns from a file
  200. void FI_GenerateListPatterns(struct Search *search)
  201. {
  202.    char buf[SIZE_PATTERN], pattern[SIZE_PATTERN];
  203.    FILE *fh;
  204.    if (fh = fopen(search->Match, "r"))
  205.    {
  206.       FreeData2D(&(search->List));
  207.       while (GetLine(fh, buf, SIZE_PATTERN)) if (*buf)
  208.       {
  209.          if (search->CaseSens) ParsePattern      (buf, pattern, SIZE_PATTERN);
  210.          else                  ParsePatternNoCase(buf, pattern, SIZE_PATTERN);
  211.          strcpy(AllocData2D(&search->List, SIZE_PATTERN), pattern);
  212.       }
  213.       fclose(fh);
  214.    }
  215. }
  216. ///
  217. /// FI_PrepareSearch
  218. //  Initializes Search structure
  219. BOOL FI_PrepareSearch(struct Search *search, int mode, BOOL casesens, int persmode, int compar, int stat, BOOL substr, char *match, char *field)
  220. {
  221.    clear(search, sizeof(struct Search));
  222.    search->Mode      = mode;
  223.    search->CaseSens  = casesens;
  224.    search->PersMode  = persmode;
  225.    search->Compare   = compar;
  226.    search->Status    = stat;
  227.    search->SubString = substr;
  228.    stccpy(search->Match, match, SIZE_PATTERN);
  229.    stccpy(search->Field, field, SIZE_DEFAULT);
  230.    search->Pattern = search->PatBuf;
  231.    search->Fast = FS_NONE;
  232.    switch (mode)
  233.    {
  234.       case 0:  search->Fast = FS_FROM; break;
  235.       case 1:  search->Fast = FS_TO; break;
  236.       case 2:  search->Fast = FS_CC; break;
  237.       case 3:  search->Fast = FS_REPLYTO; break;
  238.       case 4:  search->Fast = FS_SUBJECT; break;
  239.       case 5:  search->Fast = FS_DATE; break;
  240.       case 6:  search->Fast = FI_IsFastSearch(field); break;
  241.       case 7:  search->Fast = FS_SIZE; break;
  242.       case 8: case 10: *search->Field = 0;
  243.    }
  244.    if (search->Fast == FS_DATE)
  245.    {
  246.       char *time;
  247.       search->DT.dat_Format = FORMAT_DOS;
  248.       search->DT.dat_StrDate = match;
  249.       search->DT.dat_StrTime = (time = strchr(match,' ')) ? time+1 : "00:00:00";
  250.       if (!StrToDate(&(search->DT)))
  251.       {
  252.          ER_NewError(GetStr(MSG_ER_ErrorDateFormat), DateStamp2String(NULL,DSS_DATE), NULL);
  253.          return FALSE;
  254.       };
  255.       search->Pattern = (char *)&(search->DT.dat_Stamp);
  256.    }
  257.    if (search->Fast == FS_SIZE)
  258.    {
  259.       search->Size = atol(match);
  260.    }
  261.    if (compar == 4) FI_GenerateListPatterns(search);
  262.    else if (search->Fast != FS_DATE && search->Fast != FS_SIZE && mode != 11)
  263.    {
  264.       if (substr || mode >= 8) FI_MakeSubstringPattern(search->Match);
  265.       if (casesens) ParsePattern      (search->Match, search->Pattern, SIZE_PATTERN);
  266.       else          ParsePatternNoCase(search->Match, search->Pattern, SIZE_PATTERN);
  267.    }
  268. }
  269. ///
  270. /// FI_DoSearch
  271. //  Checks if a message fulfills the search criteria
  272. BOOL FI_DoSearch(struct Search *search, struct Mail *mail)
  273. {
  274.    BOOL found0, found = FALSE;
  275.    int comp_bak = search->Compare, mstat;
  276.    switch (search->Mode)
  277.    {
  278.       case 0: case 1: case 2: case 3: case 4: case 5: case 6:  case 7:
  279.          found = search->Fast == FS_NONE ? FI_SearchPatternInHeader(search, mail)
  280.                                          : FI_SearchPatternFast(search, mail);
  281.                break;
  282.       case 8:  search->Compare = 0;
  283.                found0 = FI_SearchPatternInHeader(search, mail);
  284.                search->Compare = comp_bak;
  285.                if (found0 == (search->Compare == 0)) found = TRUE;
  286.                break;
  287.       case 9:  search->Compare = 0;
  288.                found0 = FI_SearchPatternInBody(search, mail);
  289.                search->Compare = comp_bak;
  290.                if (found0 == (search->Compare == 0)) found = TRUE;
  291.                break;
  292.       case 10: search->Compare = 0;
  293.                if (!(found0 = FI_SearchPatternInHeader(search, mail)))
  294.                found0 = FI_SearchPatternInBody(search, mail);
  295.                search->Compare = comp_bak;
  296.                if (found0 == (search->Compare == 0)) found = TRUE;
  297.                break;
  298.       case 11: if ((mstat = mail->Status) == 8) mstat = 0; /* new=unread */
  299.                if ((search->Compare == 0 && search->Status == mstat) || (search->Compare == 1 && search->Status != mstat)) found = TRUE;
  300.                break;
  301.    }
  302.    return found;
  303. }
  304. ///
  305. /// FI_DoComplexSearch
  306. //  Does a complex search with two combined criteria
  307. BOOL FI_DoComplexSearch(struct Search *search1, int combine, struct Search *search2, struct Mail *mail)
  308. {
  309.    BOOL found1;
  310.    found1 = FI_DoSearch(search1, mail);
  311.    switch (combine)
  312.    {
  313.       case 0: return found1;
  314.       case 1: if (found1) return TRUE;
  315.               return FI_DoSearch(search2, mail);
  316.       case 2: if (!found1) return FALSE;
  317.               return FI_DoSearch(search2, mail);
  318.       case 3: return (BOOL)(found1 != FI_DoSearch(search2, mail));
  319.    }
  320. }
  321. ///
  322. /// FI_SearchFunc
  323. //  Starts the search and shows progress
  324. SAVEDS void FI_SearchFunc(void)
  325. {
  326.    int pg, sfonum = 0, fnr, id, i, fndmsg = 0, totmsg = 0, progress = 0;
  327.    struct FI_GUIData *gui = &G->FI->GUI;
  328.    struct Folder **sfo, *folder;
  329.    char *name, *match, *field;
  330.    static char gauge[40];
  331.    struct Mail *mail;
  332.    APTR ga = gui->GA_PROGRESS;
  333.    struct SearchGroup *gdata = &gui->GR_SEARCH;
  334.    struct Search search;
  335.  
  336.    set(gui->WI, MUIA_Window_ActiveObject, MUIV_Window_ActiveObject_None);
  337.    set(gui->BT_SELECT, MUIA_Disabled, TRUE);
  338.    set(gui->BT_READ, MUIA_Disabled, TRUE);
  339.    DoMethod(gui->LV_MAILS, MUIM_NList_Clear);
  340.    get(gui->LV_FOLDERS, MUIA_List_Entries, &fnr);
  341.    sfo = calloc(fnr, sizeof(struct Folder *));
  342.    id = MUIV_List_NextSelected_Start;
  343.    while (TRUE)
  344.    {
  345.       DoMethod(gui->LV_FOLDERS, MUIM_List_NextSelected, &id);
  346.       if (id == MUIV_List_NextSelected_End) break;
  347.       DoMethod(gui->LV_FOLDERS, MUIM_List_GetEntry, id, &name);
  348.       if (folder = FO_GetFolderByName(name, NULL)) if (MA_GetIndex(folder))
  349.       {
  350.          sfo[sfonum++] = folder;
  351.          totmsg += folder->Total;
  352.       }
  353.    }
  354.    if (!totmsg) { free(sfo); return; }
  355.    get(gdata->PG_SRCHOPT, MUIA_Group_ActivePage, &pg);
  356.    get(gdata->ST_MATCH[pg], MUIA_String_Contents, &match);
  357.    get(gdata->ST_FIELD, MUIA_String_Contents, &field);
  358.    FI_PrepareSearch(&search, GetMUICycle(gdata->CY_MODE),
  359.       GetMUICheck(gdata->CH_CASESENS[pg]), GetMUIRadio(gdata->RA_ADRMODE),
  360.       GetMUICycle(gdata->CY_COMP[pg]), GetMUICycle(gdata->CY_STATUS),
  361.       pg < 2 ? GetMUICheck(gdata->CH_SUBSTR[pg]) : (pg == 4 ? TRUE : FALSE),
  362.       match, field);
  363.    sprintf(gauge, GetStr(MSG_FI_GaugeText), totmsg);
  364.    set(ga, MUIA_Gauge_InfoText, gauge);
  365.    set(ga, MUIA_Gauge_Max, totmsg);
  366.    set(ga, MUIA_Gauge_Current, 0);
  367.    set(gui->GR_PAGE, MUIA_Group_ActivePage, 1);
  368.    G->FI->Abort = FALSE;
  369.    for (i = 0; i < sfonum && !G->FI->Abort; i++)
  370.    {
  371.       for (mail = sfo[i]->Messages; mail && !G->FI->Abort; mail = mail->Next)
  372.       {
  373.          DoMethod(G->App,MUIM_Application_InputBuffered);
  374.          if (FI_DoSearch(&search, mail))
  375.          {
  376.             DoMethod(gui->LV_MAILS, MUIM_NList_InsertSingle, mail, MUIV_NList_Insert_Bottom);
  377.             fndmsg++;
  378.          }
  379.          set(ga, MUIA_Gauge_Current, ++progress);
  380.       }
  381.    }
  382.    FreeData2D(&(search.List));
  383.    free(sfo);
  384.    set(gui->GR_PAGE, MUIA_Group_ActivePage, 0);
  385.    set(gui->BT_SELECT, MUIA_Disabled, !fndmsg);
  386.    set(gui->BT_READ, MUIA_Disabled, !fndmsg);
  387. }
  388. MakeHook(FI_SearchHook,FI_SearchFunc);
  389. ///
  390. /// FI_ToRuleFunc
  391. //  Creates a filter from the current search options
  392. SAVEDS void FI_ToRuleFunc(void)
  393. {
  394.    int ch, i, r = -1;
  395.  
  396.    for (i = 0; i < MAXRU; i++) if (!C->RU[i]) { r = i; break; }
  397.    if (r >= 0)
  398.    {
  399.       char name[SIZE_NAME];
  400.       *name = 0;
  401.       if (ch = StringRequest(name, SIZE_NAME, GetStr(MSG_FI_AddFilter), GetStr(MSG_FI_AddFilterReq), GetStr(MSG_Save), GetStr(MSG_Use), GetStr(MSG_Cancel), FALSE, G->FI->GUI.WI))
  402.          if (C->RU[r] = CO_NewRule())
  403.          {
  404.             struct SearchGroup *grp = &(G->FI->GUI.GR_SEARCH);
  405.             int g;
  406.             get(grp->PG_SRCHOPT, MUIA_Group_ActivePage, &g);
  407.             strcpy(C->RU[r]->Name, name);
  408.             C->RU[r]->ApplyOnReq = C->RU[r]->ApplyToNew = TRUE;
  409.             C->RU[r]->Field[0]      = GetMUICycle(grp->CY_MODE);
  410.             C->RU[r]->SubField[0]   = GetMUIRadio(grp->RA_ADRMODE);
  411.             GetMUIString(C->RU[r]->CustomField[0], grp->ST_FIELD);
  412.             C->RU[r]->Comparison[0] = GetMUICycle(grp->CY_COMP[g]);
  413.             if (grp->ST_MATCH[g]) GetMUIString(C->RU[r]->Match[0], grp->ST_MATCH[g]);
  414.                              else strcpy(C->RU[r]->Match[0], Status[GetMUICycle(grp->CY_STATUS)]);
  415.             if (grp->CH_CASESENS[g]) C->RU[r]->CaseSens[0]  = GetMUICheck(grp->CH_CASESENS[g]);
  416.             if (grp->CH_SUBSTR[g]  ) C->RU[r]->Substring[0] = GetMUICheck(grp->CH_SUBSTR[g]);
  417.             if (ch == 1) CO_SaveConfig(C, G->CO_PrefsFile);
  418.          }
  419.    }
  420.    else ER_NewError(GetStr(MSG_ER_ErrorMaxFilters), NULL, NULL);
  421. }
  422. MakeHook(FI_ToRuleHook,FI_ToRuleFunc);
  423. ///
  424. /// FI_Open
  425. //  Opens find window
  426. SAVEDS void FI_Open(void)
  427. {
  428.    int i, j, apos = 0;
  429.    struct Folder **flist, *folder;
  430.  
  431.    if (!G->FI)
  432.    {
  433.       if (!(G->FI = FI_New())) return;
  434.       folder = FO_GetCurrentFolder();
  435.       flist = FO_CreateList();
  436.       for (j = 0, i = 1; i <= (int)*flist; i++) if (flist[i]->Type != FT_SEPARATOR)
  437.       {
  438.          DoMethod(G->FI->GUI.LV_FOLDERS, MUIM_List_InsertSingle, flist[i]->Name, MUIV_List_Insert_Bottom);
  439.          if (flist[i] == folder) apos = j;
  440.          j++;
  441.       }
  442.       set(G->FI->GUI.LV_FOLDERS, MUIA_List_Active, apos);
  443.       free(flist);
  444.    }
  445.    if (!SafeOpenWindow(G->FI->GUI.WI)) DisposeModulePush(&G->FI);
  446. }
  447. MakeHook(FI_OpenHook,FI_Open);
  448. ///
  449. /// FI_SearchGhost
  450. //  Enables/disables gadgets in search form
  451. void FI_SearchGhost(struct SearchGroup *gdata, BOOL disabled)
  452. {
  453.    int mode = GetMUICycle(gdata->CY_MODE), i;
  454.    int oper = GetMUICycle(gdata->CY_COMP[Mode2Group[mode]]);
  455.    set(gdata->CY_MODE, MUIA_Disabled, disabled);
  456.    set(gdata->ST_FIELD, MUIA_Disabled, disabled || mode != 6);
  457.    set(gdata->RA_ADRMODE, MUIA_Disabled, disabled);
  458.    set(gdata->CY_STATUS, MUIA_Disabled, disabled);
  459.    for (i = 0; i < 5; i++)
  460.    {
  461.       set(gdata->CY_COMP[i], MUIA_Disabled, disabled);
  462.       if (gdata->ST_MATCH[i]) set(gdata->ST_MATCH[i], MUIA_Disabled, disabled);
  463.       if (gdata->CH_CASESENS[i]) set(gdata->CH_CASESENS[i], MUIA_Disabled, disabled);
  464.       if (gdata->CH_SUBSTR[i]) set(gdata->CH_SUBSTR[i], MUIA_Disabled, disabled || oper == 4 || (i < 2 && oper > 1));
  465.       if (gdata->BT_FILE[i]) set(gdata->BT_FILE[i], MUIA_Disabled, disabled || oper != 4);
  466.       if (gdata->BT_EDIT[i]) set(gdata->BT_EDIT[i], MUIA_Disabled, disabled || oper != 4);
  467.    }
  468. }
  469. ///
  470. /// FI_SearchOptFunc
  471. //  Selects correct form for search mode
  472. SAVEDS ASM void FI_SearchOptFunc(REG(a1) ULONG *arg)
  473. {
  474.    struct SearchGroup *gdata = (struct SearchGroup *)arg[0];
  475.    int mode = GetMUICycle(gdata->CY_MODE);
  476.    set(gdata->PG_SRCHOPT, MUIA_Group_ActivePage, Mode2Group[mode]);
  477.    FI_SearchGhost(gdata, FALSE);
  478. }
  479. MakeHook(FI_SearchOptHook, FI_SearchOptFunc);
  480. ///
  481. /// FI_EditFileFunc
  482. //  Edits pattern list in text editor
  483. SAVEDS ASM void FI_EditFileFunc(REG(a1) int *arg)
  484. {
  485.    if (*C->Editor)
  486.    {
  487.       char buffer[SIZE_COMMAND+SIZE_PATHFILE];
  488.       sprintf(buffer,"%s \"%s\"", C->Editor, GetMUIStringPtr((struct Object *)arg[0]));
  489.       ExecuteCommand(buffer, TRUE, OUT_NIL);
  490.    }
  491. }
  492. MakeHook(FI_EditFileHook,FI_EditFileFunc);
  493. ///
  494. /// FI_ConstructSearchGroup
  495. //  Creates search form
  496. APTR FI_ConstructSearchGroup(struct SearchGroup *gdata, BOOL remote)
  497. {
  498.    static char *fldopt[2][13], *compopt[14], *statopt[9], *amode[3];
  499.    APTR grp;
  500.    int f = remote ? 1 : 0;
  501.  
  502.    amode[0] = GetStr(MSG_Address);
  503.    amode[1] = GetStr(MSG_Name);
  504.    amode[2] = NULL;
  505.    statopt[0] = GetStr(MSG_FI_StatNew);
  506.    statopt[1] = GetStr(MSG_FI_StatRead);
  507.    statopt[2] = GetStr(MSG_FI_StatForwarded);
  508.    statopt[3] = GetStr(MSG_FI_StatReplied);
  509.    statopt[4] = GetStr(MSG_FI_StatQueued);
  510.    statopt[5] = GetStr(MSG_FI_StatFailed);
  511.    statopt[6] = GetStr(MSG_FI_StatHold);
  512.    statopt[7] = GetStr(MSG_FI_StatSent);
  513.    statopt[8] = NULL;
  514.    compopt[0] = compopt[5] = compopt[ 8] = " = ";
  515.    compopt[1] = compopt[6] = compopt[ 9] = " <> ";
  516.    compopt[2] =              compopt[10] = " < ";
  517.    compopt[3] =              compopt[11] = " > ";
  518.                              compopt[12] = " IN ";
  519.    compopt[4] = compopt[7] = compopt[13] = NULL;
  520.    fldopt[f][0] = GetStr(MSG_FI_FromField);
  521.    fldopt[f][1] = GetStr(MSG_FI_ToField);
  522.    fldopt[f][2] = GetStr(MSG_FI_CCField);
  523.    fldopt[f][3] = GetStr(MSG_FI_ReplyToField);
  524.    fldopt[f][4] = GetStr(MSG_FI_SubjectField);
  525.    fldopt[f][5] = GetStr(MSG_FI_DateField);
  526.    fldopt[f][6] = GetStr(MSG_FI_OtherField);
  527.    fldopt[f][7] = GetStr(MSG_FI_MessageSize);
  528.    fldopt[f][8] = GetStr(MSG_FI_MessageHeader);
  529.    fldopt[f][9] = remote ? NULL : GetStr(MSG_FI_MessageBody);
  530.    fldopt[f][10]= GetStr(MSG_FI_WholeMessage);
  531.    fldopt[f][11]= GetStr(MSG_Status);
  532.    fldopt[f][12]= NULL;
  533.    grp = VGroup,
  534.       MUIA_HelpNode, "FI_K",
  535.       Child, HGroup,
  536.          Child, Label1(GetStr(MSG_FI_SearchIn)),
  537.             Child, gdata->CY_MODE = MakeCycle(fldopt[f],GetStr(MSG_FI_SearchIn)),
  538.             Child, gdata->ST_FIELD = MakeString(SIZE_DEFAULT, ""),
  539.          End,
  540.          Child, gdata->PG_SRCHOPT = PageGroup,
  541.             Child, VGroup, /* 0  from, to, cc, reply-to */
  542.                Child, HGroup,
  543.                   MUIA_Group_HorizSpacing, 0,
  544.                   Child, gdata->CY_COMP[0] = MakeCycle(&compopt[8],""),
  545.                   Child, HSpace(4),
  546.                   Child, PopaslObject,
  547.                      MUIA_Popasl_Type     ,ASL_FileRequest,
  548.                      MUIA_Popstring_String,gdata->ST_MATCH[0] = MakeString(SIZE_PATTERN,""),
  549.                      MUIA_Popstring_Button,gdata->BT_FILE[0] = PopButton(MUII_PopFile),
  550.                   End,
  551.                   Child, gdata->BT_EDIT[0] = PopButton(MUII_PopUp),
  552.                End,
  553.                Child, HGroup,
  554.                   Child, VGroup,
  555.                      Child, MakeCheckGroup((Object **)&gdata->CH_CASESENS[0], GetStr(MSG_FI_CaseSensitive)),
  556.                      Child, MakeCheckGroup((Object **)&gdata->CH_SUBSTR[0], GetStr(MSG_FI_SubString)),
  557.                   End,
  558.                   Child, gdata->RA_ADRMODE = Radio(NULL, amode),
  559.                End,
  560.             End,
  561.             Child, VGroup, /* 1  subject, other field */
  562.                Child, HGroup,
  563.                   MUIA_Group_HorizSpacing, 0,
  564.                   Child, gdata->CY_COMP[1] = MakeCycle(&compopt[8],""),
  565.                   Child, HSpace(4),
  566.                   Child, PopaslObject,
  567.                      MUIA_Popasl_Type     ,ASL_FileRequest,
  568.                      MUIA_Popstring_String,gdata->ST_MATCH[1] = MakeString(SIZE_PATTERN,""),
  569.                      MUIA_Popstring_Button,gdata->BT_FILE[1] = PopButton(MUII_PopFile),
  570.                   End,
  571.                   Child, gdata->BT_EDIT[1] = PopButton(MUII_PopUp),
  572.                End,
  573.                Child, VGroup,
  574.                   Child, MakeCheckGroup((Object **)&gdata->CH_CASESENS[1], GetStr(MSG_FI_CaseSensitive)),
  575.                   Child, MakeCheckGroup((Object **)&gdata->CH_SUBSTR[1], GetStr(MSG_FI_SubString)),
  576.                End,
  577.             End,
  578.             Child, VGroup, /* 2  date, size */
  579.                Child, HGroup,
  580.                   Child, gdata->CY_COMP[2] = MakeCycle(compopt,""),
  581.                   Child, gdata->ST_MATCH[2] = MakeString(SIZE_PATTERN,""),
  582.                End,
  583.                Child, HVSpace,
  584.             End,
  585.             Child, VGroup, /* 3  status */
  586.                Child, HGroup,
  587.                   Child, gdata->CY_COMP[3] = MakeCycle(&compopt[5],""),
  588.                   Child, gdata->CY_STATUS = MakeCycle(statopt,""),
  589.                   Child, HSpace(0),
  590.                End,
  591.                Child, HVSpace,
  592.             End,
  593.             Child, VGroup, /* 4  message header/body */
  594.                Child, HGroup,
  595.                   Child, gdata->CY_COMP[4] = MakeCycle(&compopt[5],""),
  596.                   Child, gdata->ST_MATCH[4] = MakeString(SIZE_PATTERN,""),
  597.                End,
  598.                Child, MakeCheckGroup((Object **)&gdata->CH_CASESENS[4], GetStr(MSG_FI_CaseSensitive)),
  599.                Child, HVSpace,
  600.             End,
  601.          End,
  602.       End;
  603.    if (grp)
  604.    {
  605.       int i;
  606.       set(gdata->RA_ADRMODE, MUIA_CycleChain, 1);
  607.       SetHelp(gdata->CY_MODE,   MSG_HELP_FI_CY_MODE);
  608.       SetHelp(gdata->ST_FIELD,  MSG_HELP_FI_ST_FIELD);
  609.       SetHelp(gdata->RA_ADRMODE,MSG_HELP_FI_RA_ADRMODE);
  610.       SetHelp(gdata->CY_STATUS, MSG_HELP_FI_CY_STATUS);
  611.       for (i = 0; i < 5; i++)
  612.       {
  613.          if (gdata->ST_MATCH[i])    SetHelp(gdata->ST_MATCH[i], MSG_HELP_FI_ST_MATCH);
  614.          if (gdata->CH_CASESENS[i]) SetHelp(gdata->CH_CASESENS[i], MSG_HELP_FI_CH_CASESENS);
  615.          if (gdata->CH_SUBSTR[i])   SetHelp(gdata->CH_SUBSTR[i], MSG_HELP_FI_CH_SUBSTR);
  616.          if (gdata->BT_EDIT[i])     DoMethod(gdata->BT_EDIT[i], MUIM_Notify, MUIA_Pressed, FALSE, MUIV_Notify_Application, 3, MUIM_CallHook, &FI_EditFileHook, gdata->ST_MATCH[i]);
  617.          SetHelp(gdata->CY_COMP[i], MSG_HELP_FI_CY_COMP);
  618.          set(gdata->CY_COMP[i], MUIA_HorizWeight, 0);
  619.          DoMethod(gdata->CY_COMP[i], MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, MUIV_Notify_Application, 3, MUIM_CallHook, &FI_SearchOptHook, gdata);
  620.       }
  621.       FI_SearchGhost(gdata, FALSE);
  622.       DoMethod(gdata->CY_MODE, MUIM_Notify, MUIA_Cycle_Active, MUIV_EveryTime, MUIV_Notify_Application, 3, MUIM_CallHook, &FI_SearchOptHook, gdata);
  623.    }
  624.    return grp;
  625. }
  626. ///
  627. /// FI_SwitchFunc
  628. //  Sets active folder according to the selected message in the results window
  629. SAVEDS void FI_SwitchFunc(void)
  630. {
  631.    struct Mail *mail;
  632.    struct MailInfo *mi;
  633.    DoMethod(G->FI->GUI.LV_MAILS, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &mail);
  634.    if (mail)
  635.    {
  636.       MA_ChangeFolder(mail->Folder);
  637.       mi = GetMailInfo(mail);
  638.       set(G->MA->GUI.NL_MAILS, MUIA_NList_Active, mi->Pos);
  639.    }
  640. }
  641. MakeHook(FI_SwitchHook, FI_SwitchFunc);
  642. ///
  643. /// FI_ReadFunc
  644. //  Reads a message listed in the results window
  645. SAVEDS void FI_ReadFunc(void)
  646. {
  647.    struct Mail *mail;
  648.    int winnum;
  649.    DoMethod(G->FI->GUI.LV_MAILS, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &mail);
  650.    if (mail) if ((winnum = RE_Open(-1, TRUE)) != -1)
  651.    {
  652.       if (SafeOpenWindow(G->RE[winnum]->GUI.WI)) RE_ReadMessage(winnum, mail); else DisposeModulePush(G->RE[winnum]);
  653.    }
  654. }
  655. MakeHook(FI_ReadHook, FI_ReadFunc);
  656. ///
  657. /// FI_SelectFunc
  658. //  Selects matching messages in the main message list
  659. SAVEDS void FI_SelectFunc(void)
  660. {
  661.    int i;
  662.    struct Folder *folder = FO_GetCurrentFolder();
  663.  
  664.    DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_Select, MUIV_NList_Select_All, MUIV_NList_Select_Off, NULL);
  665.    for (i = 0; ; i++)
  666.    {
  667.       struct Mail *mail;
  668.       DoMethod(G->FI->GUI.LV_MAILS, MUIM_NList_GetEntry, i, &mail);
  669.       if (!mail) break;
  670.       if (mail->Folder == folder)
  671.       {
  672.          struct MailInfo *mi = GetMailInfo(mail);
  673.          DoMethod(G->MA->GUI.NL_MAILS, MUIM_NList_Select, mi->Pos, MUIV_NList_Select_On, NULL);
  674.       }
  675.    }
  676. }
  677. MakeHook(FI_SelectHook, FI_SelectFunc);
  678. ///
  679. /// FI_Close
  680. //  Closes find window
  681. SAVEDS void FI_Close(void)
  682. {
  683.    DisposeModulePush(&G->FI);
  684. }
  685. MakeHook(FI_CloseHook, FI_Close);
  686. ///
  687.  
  688. /*** GUI ***/
  689. /// FI_PO_InitRuleListFunc
  690. //  Creates a popup list of configured filters
  691. SAVEDS ASM long FI_PO_InitRuleListFunc(REG(a2) Object *pop)
  692. {  
  693.    int i;
  694.    DoMethod(pop, MUIM_List_Clear);
  695.    for (i = 0; i < MAXRU; i++) if (C->RU[i])
  696.       DoMethod(pop, MUIM_List_InsertSingle, C->RU[i], MUIV_List_Insert_Bottom);
  697.    return TRUE;
  698. }
  699. MakeHook(FI_PO_InitRuleListHook, FI_PO_InitRuleListFunc);
  700. ///
  701. /// FI_PO_FromRuleFunc
  702. //  Gets search options from selected filter
  703. SAVEDS ASM void FI_PO_FromRuleFunc(REG(a2) Object *pop)
  704. {
  705.    struct Rule *rule;
  706.    DoMethod(pop, MUIM_List_GetEntry, MUIV_List_GetEntry_Active, &rule);
  707.    if (rule) 
  708.    {
  709.       struct SearchGroup *grp = &(G->FI->GUI.GR_SEARCH);
  710.       int i, g = Mode2Group[rule->Field[0]];
  711.       setcycle (grp->CY_MODE,   rule->Field[0]);
  712.       setmutex (grp->RA_ADRMODE,rule->SubField[0]);
  713.       setstring(grp->ST_FIELD,  rule->CustomField[0]);
  714.       setcycle (grp->CY_COMP[g],rule->Comparison[0]);
  715.       if (grp->ST_MATCH[g]) setstring(grp->ST_MATCH[g], rule->Match[0]);
  716.       else for (i = 0; i < 8; i++)
  717.          if (!stricmp(rule->Match[0], Status[i])) setcycle(grp->CY_STATUS, i);
  718.       if (grp->CH_CASESENS[g]) setcheckmark(grp->CH_CASESENS[g],rule->CaseSens[0]);
  719.       if (grp->CH_SUBSTR[g]  ) setcheckmark(grp->CH_SUBSTR[g],  rule->Substring[0]);
  720.    }
  721. }
  722. MakeHook(FI_PO_FromRuleHook, FI_PO_FromRuleFunc);
  723. ///
  724. /// FI_New
  725. //  Creates find window
  726. struct FI_ClassData *FI_New(void)
  727. {
  728.    struct FI_ClassData *data;
  729.  
  730.    if (data = calloc(1,sizeof(struct FI_ClassData)))
  731.    {
  732.       APTR bt_search, bt_abort, lv_fromrule, bt_torule, po_fromrule, bt_all;
  733.       data->GUI.WI = WindowObject,
  734.          MUIA_Window_Title, GetStr(MSG_FI_FindMessages),
  735.          MUIA_HelpNode, "FI_W",
  736.          MUIA_Window_ID, MAKE_ID('F','I','N','D'),
  737.          WindowContents, VGroup,
  738.             Child, HGroup,
  739.                Child, VGroup, GroupFrameT(GetStr(MSG_FI_FindIn)),
  740.                   Child, ListviewObject,
  741.                      MUIA_Listview_Input, TRUE,
  742.                      MUIA_Listview_MultiSelect, TRUE,
  743.                      MUIA_CycleChain      , 1,
  744.                      MUIA_Listview_List, data->GUI.LV_FOLDERS = ListObject,
  745.                         InputListFrame,
  746.                         MUIA_List_AdjustWidth, TRUE,
  747.                      End,
  748.                   End,
  749.                   Child, bt_all = MakeButton(GetStr(MSG_FI_AllFolders)),
  750.                End,
  751.                Child, VGroup, GroupFrameT(GetStr(MSG_FI_FindWhat)),
  752.                   Child, FI_ConstructSearchGroup(&data->GUI.GR_SEARCH, FALSE),
  753.                   Child, ColGroup(2),
  754.                      Child, po_fromrule = PopobjectObject,
  755.                         MUIA_Popstring_Button, MakeButton(GetStr(MSG_FI_UseFilter)),
  756.                         MUIA_Popobject_ObjStrHook, &FI_PO_FromRuleHook,
  757.                         MUIA_Popobject_StrObjHook, &FI_PO_InitRuleListHook,
  758.                         MUIA_Popobject_WindowHook, &PO_WindowHook,
  759.                         MUIA_Popobject_Object, lv_fromrule = ListviewObject,
  760.                            MUIA_Listview_List, ListObject, InputListFrame,
  761.                            End,
  762.                         End,
  763.                      End,
  764.                      Child, bt_torule = MakeButton(GetStr(MSG_FI_AddAsFilter)),
  765.                   End,
  766.                End,
  767.             End,
  768.             Child, VGroup, GroupFrameT(GetStr(MSG_FI_Results)),
  769.                Child, NListviewObject,
  770.                   MUIA_CycleChain,1,
  771.                   MUIA_NListview_NList, data->GUI.LV_MAILS = NListObject,
  772.                      MUIA_NList_MinColSortable, 0,
  773.                      MUIA_NList_TitleClick    , TRUE,
  774.                      MUIA_NList_TitleClick2   , TRUE,
  775.                      MUIA_NList_MultiSelect   , MUIV_NList_MultiSelect_Default,
  776.                      MUIA_NList_CompareHook2  , &MA_LV_Cmp2Hook,
  777.                      MUIA_NList_Format        , "COL=7 W=-1 BAR,COL=1 MICW=20 BAR,COL=3 MICW=16 BAR,COL=4 MICW=9 MACW=15 BAR,COL=5 W=-1 MACW=9 P=\33r BAR",
  778.                      MUIA_NList_DoubleClick   , TRUE,
  779.                      MUIA_NList_DisplayHook   , &MA_LV_DspFuncHook,
  780.                      MUIA_NList_AutoVisible   , TRUE,
  781.                      MUIA_NList_Title         , TRUE,
  782.                      MUIA_NList_TitleSeparator, TRUE,
  783.                      MUIA_Font, C->FixedFontList ? MUIV_NList_Font_Fixed : MUIV_NList_Font,
  784.                   End,
  785.                End,
  786.             End,
  787.             Child, data->GUI.GR_PAGE = PageGroup,
  788.                Child, ColGroup(3),
  789.                   Child, bt_search = MakeButton(GetStr(MSG_FI_StartSearch)),
  790.                   Child, data->GUI.BT_SELECT = MakeButton(GetStr(MSG_FI_SelectMatched)),
  791.                   Child, data->GUI.BT_READ = MakeButton(GetStr(MSG_FI_ReadMessage)),
  792.                End,
  793.                Child, HGroup,
  794.                   Child, data->GUI.GA_PROGRESS = GaugeObject,
  795.                      MUIA_HorizWeight, 200,
  796.                      GaugeFrame,
  797.                      MUIA_Gauge_Horiz   ,TRUE,
  798.                   End,
  799.                   Child, bt_abort = MakeButton(GetStr(MSG_FI_Abort)),
  800.                End,
  801.             End,
  802.          End,
  803.       End;
  804.       if (data->GUI.WI)
  805.       {
  806.          set(data->GUI.BT_SELECT, MUIA_Disabled, TRUE);
  807.          set(data->GUI.BT_READ, MUIA_Disabled, TRUE);
  808.          SetHelp(data->GUI.LV_FOLDERS   ,MSG_HELP_FI_LV_FOLDERS);
  809.          SetHelp(bt_all                 ,MSG_HELP_FI_BT_ALL);
  810.          SetHelp(po_fromrule            ,MSG_HELP_FI_PO_FROMRULE);
  811.          SetHelp(bt_torule              ,MSG_HELP_FI_BT_TORULE);
  812.          SetHelp(bt_search              ,MSG_HELP_FI_BT_SEARCH);
  813.          SetHelp(data->GUI.BT_SELECT    ,MSG_HELP_FI_BT_SELECT);
  814.          SetHelp(data->GUI.BT_READ      ,MSG_HELP_FI_BT_READ);
  815.          SetHelp(bt_abort               ,MSG_HELP_FI_BT_ABORT);
  816.          DoMethod(G->App, OM_ADDMEMBER, data->GUI.WI);
  817.          DoMethod(bt_abort           ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,3,MUIM_WriteLong,TRUE,&(data->Abort));
  818.          DoMethod(lv_fromrule        ,MUIM_Notify,MUIA_Listview_DoubleClick,TRUE          ,po_fromrule            ,2,MUIM_Popstring_Close,TRUE);
  819.          DoMethod(bt_all             ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,data->GUI.LV_FOLDERS   ,5,MUIM_List_Select,MUIV_List_Select_All,MUIV_List_Select_On,NULL);
  820.          DoMethod(bt_torule          ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,2,MUIM_CallHook,&FI_ToRuleHook);
  821.          DoMethod(bt_search          ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,2,MUIM_CallHook,&FI_SearchHook);
  822.          DoMethod(data->GUI.BT_SELECT,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,2,MUIM_CallHook,&FI_SelectHook);
  823.          DoMethod(data->GUI.LV_MAILS ,MUIM_Notify,MUIA_NList_TitleClick    ,MUIV_EveryTime,MUIV_Notify_Self       ,4,MUIM_NList_Sort3,MUIV_TriggerValue,MUIV_NList_SortTypeAdd_2Values,MUIV_NList_Sort3_SortType_Both);
  824.          DoMethod(data->GUI.LV_MAILS ,MUIM_Notify,MUIA_NList_TitleClick2   ,MUIV_EveryTime,MUIV_Notify_Self       ,4,MUIM_NList_Sort3,MUIV_TriggerValue,MUIV_NList_SortTypeAdd_2Values,MUIV_NList_Sort3_SortType_2);
  825.          DoMethod(data->GUI.LV_MAILS ,MUIM_Notify,MUIA_NList_SortType      ,MUIV_EveryTime,MUIV_Notify_Self       ,3,MUIM_Set,MUIA_NList_TitleMark,MUIV_TriggerValue);
  826.          DoMethod(data->GUI.LV_MAILS ,MUIM_Notify,MUIA_NList_SortType2     ,MUIV_EveryTime,MUIV_Notify_Self       ,3,MUIM_Set,MUIA_NList_TitleMark2,MUIV_TriggerValue);
  827.          DoMethod(data->GUI.LV_MAILS ,MUIM_Notify,MUIA_NList_Active        ,MUIV_EveryTime,MUIV_Notify_Application,2,MUIM_CallHook,&FI_SwitchHook);
  828.          DoMethod(data->GUI.LV_MAILS ,MUIM_Notify,MUIA_NList_DoubleClick   ,MUIV_EveryTime,MUIV_Notify_Application,2,MUIM_CallHook,&FI_ReadHook);
  829.          DoMethod(data->GUI.BT_READ  ,MUIM_Notify,MUIA_Pressed             ,FALSE         ,MUIV_Notify_Application,2,MUIM_CallHook,&FI_ReadHook);
  830.          DoMethod(data->GUI.WI       ,MUIM_Notify,MUIA_Window_CloseRequest ,TRUE          ,MUIV_Notify_Application,2,MUIM_CallHook,&FI_CloseHook);
  831.          return data;
  832.       }
  833.       free(data);
  834.    }
  835.    return NULL;
  836. }
  837. ///
  838.